// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/gl_fence_arb.h"

#include "base/strings/stringprintf.h"
#include "ui/gl/gl_bindings.h"

namespace gfx {

namespace {

    std::string GetGLErrors()
    {
        // Clears and logs all current gl errors.
        std::string accumulated_errors;
        GLenum error;
        while ((error = glGetError()) != GL_NO_ERROR) {
            accumulated_errors += base::StringPrintf("0x%x ", error);
        }
        return accumulated_errors;
    }

} // namespace

GLFenceARB::GLFenceARB()
{
    sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
    DCHECK_EQ(GL_TRUE, glIsSync(sync_));
    glFlush();
}

bool GLFenceARB::HasCompleted()
{
    // Handle the case where FenceSync failed.
    if (!sync_)
        return true;

    DCHECK_EQ(GL_TRUE, glIsSync(sync_));
    // We could potentially use glGetSynciv here, but it doesn't work
    // on OSX 10.7 (always says the fence is not signaled yet).
    // glClientWaitSync works better, so let's use that instead.
    GLenum result = glClientWaitSync(sync_, 0, 0);
    if (result == GL_WAIT_FAILED) {
        LOG(FATAL) << "Failed to wait for GLFence. error code:" << GetGLErrors();
    }
    return result != GL_TIMEOUT_EXPIRED;
}

void GLFenceARB::ClientWait()
{
    DCHECK_EQ(GL_TRUE, glIsSync(sync_));
    GLenum result = glClientWaitSync(sync_, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
    DCHECK_NE(static_cast<GLenum>(GL_TIMEOUT_EXPIRED), result);
    if (result == GL_WAIT_FAILED) {
        LOG(FATAL) << "Failed to wait for GLFence. error code:" << GetGLErrors();
    }
}

void GLFenceARB::ServerWait()
{
    DCHECK_EQ(GL_TRUE, glIsSync(sync_));
    glWaitSync(sync_, 0, GL_TIMEOUT_IGNORED);
}

GLFenceARB::~GLFenceARB()
{
    DCHECK_EQ(GL_TRUE, glIsSync(sync_));
    glDeleteSync(sync_);
}

} // namespace gfx
